<template>
  <div ref="moveWidget" :style="styleProps" @mousedown="startMove">
    <slot></slot>
    <div class="left-top" @mousedown.stop="startResize($event, 'left-top')"></div>
    <div class="right-top" @mousedown.stop="startResize($event, 'right-top')"></div>
    <div class="left-bottom" @mousedown.stop="startResize($event, 'left-bottom')"></div>
    <div class="right-bottom" @mousedown.stop="startResize($event, 'right-bottom')"></div>
    <div class="top" @mousedown.stop="startResize($event, 'top')"></div>
    <div class="bottom" @mousedown.stop="startResize($event, 'bottom')"></div>
    <div class="left" @mousedown.stop="startResize($event, 'left')"></div>
    <div class="right" @mousedown.stop="startResize($event, 'right')"></div>
  </div>
</template>

<script lang="ts">
import { defineComponent, computed, ref, reactive } from "vue";
import { pick, functions } from "lodash-es";
type ResizeDirection =
  | "left-top"
  | "right-top"
  | "left-bottom"
  | "right-bottom"
  | "top"
  | "left"
  | "bottom"
  | "right";
interface IOriginalPositions {
  left: number;
  right: number;
  top: number;
  bottom: number;
}
export default defineComponent({
  props: {
    id: {
      type: String,
      required: true,
    },
    props: {
      type: Object,
    },
  },
  setup(props, context) {
    const gap = reactive({
      x: 0,
      y: 0,
    });
    let moveWidget = ref<HTMLElement | null>(null);
    const styleProps = computed(() =>
      pick(props.props, ["position", "top", "left", "width", "height"])
    );

    // 计算实际需要移动的值
    const caculateMovePosition = (e: MouseEvent) => {
      const container = document.querySelector(".preview-viewport") as HTMLElement;
      const left = e.clientX - container.offsetLeft - gap.x;
      const top = e.clientY - container.offsetTop - gap.y + container.scrollTop;
      return {
        left,
        top,
      };
    };
    /**
     * 解析：
     * 	点击时：确定元素的到浏览器left,top的距离
     *  移动时：鼠标的x,y减去刚开始元素的left,top的位置(计算出移动的距离) 可以考虑到滚动的距离加上去
     */
    // 是否触发移动
    let isMove = false;
    let startMove = (e: MouseEvent) => {
      // 鼠标按下,计算相对位置
      const currentElement = moveWidget.value as HTMLElement;
      let { left, top } = currentElement.getBoundingClientRect();
      gap.x = e.clientX - left;
      gap.y = e.clientY - top;

      let handleMove = (e: MouseEvent) => {
        isMove = true;
        let { left, top } = caculateMovePosition(e);
        // 更新页面移动的位置
        currentElement.style.top = top + "px";
        currentElement.style.left = left + "px";
      };
      let handleMouseUp = (e: MouseEvent) => {
        let { left, top } = caculateMovePosition(e);
        if (isMove) {
          isMove = false;
          // 更新props
          context.emit("updatePosition", {
            currentId: props.id,
            key: "left",
            v: left + "px",
          });
          context.emit("updatePosition", {
            currentId: props.id,
            key: "top",
            v: top + "px",
          });
        }
        // 解绑事件
        document.removeEventListener("mousemove", handleMove);
        document.removeEventListener("mouseup", handleMouseUp);
      };
      // 移动
      document.addEventListener("mousemove", handleMove);
      // 松开
      document.addEventListener("mouseup", handleMouseUp);
    };

    let caculateSize = (
      e: MouseEvent,
      direction: ResizeDirection,
      positions: IOriginalPositions
    ) => {
      const { left, right, top, bottom } = positions;
      const { pageX, pageY } = e;
      const container = document.querySelector(".preview-viewport") as HTMLElement;
      const rightWidth = pageX - left;
      const bottomHeight = pageY - top;
      const leftWidth = right - pageX;
      const topHeight = bottom - pageY;
      const leftOffset = pageX - container.offsetLeft;
      const topOffset = pageY - container.offsetTop + container.scrollTop;
      switch (direction) {
        case "left-top":
          return {
            width: leftWidth,
            height: topHeight,
            top: topOffset,
            left: leftOffset,
          };
        case "right-top":
          return {
            width: rightWidth,
            height: topHeight,
            top: topOffset,
          };
        case "left-bottom":
          return {
            width: leftWidth,
            height: bottomHeight,
            left: leftOffset,
          };
        case "right-bottom":
          return {
            width: rightWidth,
            height: bottomHeight,
          };
        case "top":
          return {
            height: topHeight,
            top: topOffset,
          };
        case "right":
          return {
            width: rightWidth,
          };
        case "left":
          return {
            width: leftWidth,
            left: leftOffset,
          };
        case "bottom":
          return {
            height: bottomHeight,
          };
        default:
          break;
      }
    };
    // 是否触发移动
    let istartResize = false;
    // 改变大小
    let startResize = (e: MouseEvent, direction: ResizeDirection) => {
      const currentElement = moveWidget.value as HTMLElement;
      // 获取当前元素的位置
      const { left, right, top, bottom } = currentElement.getBoundingClientRect();

      let handleMove = (e: MouseEvent) => {
        istartResize = true;
        let size = caculateSize(e, direction, { left, right, top, bottom });
        //  改变大小
        if (size) {
          if (size.left) {
            currentElement.style.left = size.left + "px";
          }
          if (size.top) {
            currentElement.style.top = size.top + "px";
          }
          if (size.width) {
            currentElement.style.width = size.width + "px";
          }
          if (size.height) {
            currentElement.style.height = size.height + "px";
          }
        }
      };
      let handleMouseUp = (e: MouseEvent) => {
        if (istartResize) {
          istartResize = false;
          // 更新props
          let size = caculateSize(e, direction, { left, right, top, bottom });
          if (size) {
            if (size.left) {
              context.emit("updatePosition", {
                currentId: props.id,
                key: "left",
                v: size.left + "px",
              });
            }
            if (size.top) {
              context.emit("updatePosition", {
                currentId: props.id,
                key: "top",
                v: size.top + "px",
              });
            }
            if (size.width) {
              context.emit("updatePosition", {
                currentId: props.id,
                key: "width",
                v: size.width + "px",
              });
            }

            if (size.height) {
              context.emit("updatePosition", {
                currentId: props.id,
                key: "height",
                v: size.height + "px",
              });
            }
          }
        }
        // 解绑事件
        document.removeEventListener("mousemove", handleMove);
        document.removeEventListener("mouseup", handleMouseUp);
      };
      // 移动
      document.addEventListener("mousemove", handleMove);
      // 松开
      document.addEventListener("mouseup", handleMouseUp);
    };

    return {
      moveWidget,
      styleProps,
      startMove,
      startResize,
    };
  },
});
</script>

<style lang="scss" scoped>
.preview-wrapper .active {
  .left-top,
  .right-top,
  .left-bottom,
  .right-bottom,
  .left,
  .right,
  .top,
  .bottom {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #fff;
    border: 3px solid #f60;
    position: absolute;
    display: block;
  }
  .left-top {
    left: -5px;
    top: -5px;
    cursor: nwse-resize;
  }
  .right-top {
    right: -5px;
    top: -5px;
    cursor: nesw-resize;
  }
  .left-bottom {
    left: -5px;
    bottom: -5px;
    cursor: nesw-resize;
  }
  .right-bottom {
    right: -5px;
    bottom: -5px;
    cursor: nwse-resize;
  }
  .top {
    top: -5px;
    left: 50%;
    cursor: n-resize;
    transform: translateX(-50%);
  }
  .bottom {
    bottom: -5px;
    left: 50%;
    cursor: s-resize;
    transform: translateX(-50%) !important;
  }
  .left {
    left: -5px;
    top: 50%;
    cursor: w-resize;
    transform: translateY(-50%);
  }
  .right {
    right: -5px;
    top: 50%;
    cursor: e-resize;
    transform: translateY(-50%);
  }
}
</style>
